"""进度追踪服务"""
from typing import Dict, Any, List
from datetime import datetime, timedelta
from app.core.database import RedisClient
import json


class ProgressService:
    """进度追踪服务类"""
    
    def __init__(self):
        try:
            self.redis = RedisClient.get_client()
            self.redis.ping()
        except Exception as e:
            print(f"警告: Redis连接失败，将使用内存存储: {e}")
            self.redis = None
            self._memory_storage = {}
    
    async def get_overview(self, user_id: str) -> Dict[str, Any]:
        """获取进度概览（从真实数据计算）"""
        # 获取所有学习记录
        study_days = set()
        total_questions = 0
        total_correct = 0
        daily_records = {}
        accuracy_trend = []
        
        if self.redis:
            try:
                # 扫描所有每日记录
                pattern = f"daily_record:{user_id}:*"
                keys = []
                cursor = 0
                while True:
                    cursor, batch = self.redis.scan(cursor, match=pattern, count=100)
                    keys.extend(batch)
                    if cursor == 0:
                        break
                
                # 处理每条记录
                for key in keys:
                    # 从key中提取日期: daily_record:user_id:2024-11-06
                    date_str = key.split(':')[-1]
                    study_days.add(date_str)
                    
                    # 获取该日期的所有题目记录
                    records = self.redis.hgetall(key)
                    day_questions = 0
                    day_correct = 0
                    
                    for qid, record_str in records.items():
                        try:
                            if isinstance(record_str, bytes):
                                record_str = record_str.decode('utf-8')
                            record = json.loads(record_str) if isinstance(record_str, str) else record_str
                            total_questions += 1
                            day_questions += 1
                            if record.get("is_correct", False):
                                total_correct += 1
                                day_correct += 1
                        except:
                            # 如果解析失败，跳过
                            pass
                    
                    if day_questions > 0:
                        daily_records[date_str] = {
                            "questions": day_questions,
                            "correct": day_correct,
                            "accuracy": (day_correct / day_questions * 100) if day_questions > 0 else 0
                        }
            except Exception as e:
                print(f"Redis操作失败: {e}")
        
        # 如果Redis不可用，尝试从训练服务和每日学习服务的内存存储读取
        if not self.redis:
            try:
                # 从训练服务读取
                from app.services.training_service import training_service
                if hasattr(training_service, '_daily_records'):
                    for record_key, records in training_service._daily_records.items():
                        # record_key格式: "user_id:2024-11-06"
                        if record_key.startswith(f"{user_id}:"):
                            date_str = record_key.split(':', 1)[1]
                            study_days.add(date_str)
                            
                            day_questions = 0
                            day_correct = 0
                            
                            for qid, record in records.items():
                                total_questions += 1
                                day_questions += 1
                                if record.get("is_correct", False):
                                    total_correct += 1
                                    day_correct += 1
                            
                            if day_questions > 0:
                                daily_records[date_str] = {
                                    "questions": day_questions,
                                    "correct": day_correct,
                                    "accuracy": (day_correct / day_questions * 100) if day_questions > 0 else 0
                                }
                
                # 从每日学习服务读取
                from app.services.daily_learning_service import daily_learning_service
                if hasattr(daily_learning_service, '_daily_records'):
                    for record_key, records in daily_learning_service._daily_records.items():
                        if record_key.startswith(f"{user_id}:"):
                            date_str = record_key.split(':', 1)[1]
                            study_days.add(date_str)
                            
                            day_questions = daily_records.get(date_str, {}).get("questions", 0)
                            day_correct = daily_records.get(date_str, {}).get("correct", 0)
                            
                            for qid, record in records.items():
                                # 避免重复计算（如果训练服务已经记录了）
                                if date_str not in daily_records or qid not in (training_service._daily_records.get(record_key, {}) if hasattr(training_service, '_daily_records') else {}):
                                    total_questions += 1
                                    day_questions += 1
                                    if record.get("is_correct", False):
                                        total_correct += 1
                                        day_correct += 1
                            
                            if day_questions > 0:
                                daily_records[date_str] = {
                                    "questions": day_questions,
                                    "correct": day_correct,
                                    "accuracy": (day_correct / day_questions * 100) if day_questions > 0 else 0
                                }
            except Exception as e:
                print(f"从服务读取记录失败: {e}")
        
        # 计算学习天数
        total_study_days = len(study_days)
        
        # 计算总准确率和错误率
        overall_accuracy = (total_correct / total_questions * 100) if total_questions > 0 else 0
        error_rate = ((total_questions - total_correct) / total_questions * 100) if total_questions > 0 else 0
        
        # 计算连续学习天数
        current_streak = self._calculate_streak(study_days)
        longest_streak = self._calculate_longest_streak(study_days)
        
        # 计算学习时长（估算：每题2.5分钟）
        total_study_hours = (total_questions * 2.5) / 60
        
        # 生成准确率趋势（最近7天）
        sorted_dates = sorted(daily_records.keys())[-7:]
        for date_str in sorted_dates:
            accuracy_trend.append({
                "date": date_str,
                "accuracy": daily_records[date_str]["accuracy"]
            })
        
        # 如果没有真实数据，返回0值而不是mock数据
        return {
            "user_id": user_id,
            "total_study_days": total_study_days,
            "total_study_hours": round(total_study_hours, 1),
            "total_questions": total_questions,
            "total_correct": total_correct,
            "total_wrong": total_questions - total_correct,
            "current_streak": current_streak,
            "longest_streak": longest_streak,
            "overall_accuracy": round(overall_accuracy, 1),
            "error_rate": round(error_rate, 1),
            "accuracy_trend": accuracy_trend
        }
    
    def _calculate_streak(self, study_days: set) -> int:
        """计算当前连续学习天数"""
        if not study_days:
            return 0
        
        today = datetime.now().date()
        streak = 0
        current_date = today
        
        while True:
            date_str = current_date.strftime("%Y-%m-%d")
            if date_str in study_days:
                streak += 1
                current_date -= timedelta(days=1)
            else:
                break
        
        return streak
    
    async def get_weakness_analysis(self, user_id: str) -> Dict[str, Any]:
        """
        获取薄弱环节分析（优化版本：限制扫描数量，批量获取题目）
        
        Returns:
            {
                "weak_subjects": List[Dict],  # 薄弱科目
                "weak_knowledge_points": List[Dict],  # 薄弱知识点
                "weak_difficulties": List[Dict],  # 薄弱难度级别
                "recommendations": List[str]  # 改善建议
            }
        """
        weak_subjects = {}
        weak_knowledge_points = {}
        weak_difficulties = {}
        
        # 获取所有答题记录（限制扫描数量，避免阻塞）
        if self.redis:
            try:
                pattern = f"daily_record:{user_id}:*"
                keys = []
                cursor = 0
                max_scans = 10  # 最多扫描10次，避免无限循环
                scan_count = 0
                
                while scan_count < max_scans:
                    cursor, batch = self.redis.scan(cursor, match=pattern, count=50)  # 减少每次扫描数量
                    keys.extend(batch)
                    scan_count += 1
                    if cursor == 0:
                        break
                    if len(keys) >= 50:  # 限制最多处理50个日期
                        break
                
                # 收集所有题目ID，批量获取
                question_ids = []
                answer_records = {}  # {question_id: is_correct}
                
                for key in keys:
                    try:
                        records = self.redis.hgetall(key)
                        for qid, record_str in records.items():
                            try:
                                if isinstance(record_str, bytes):
                                    record_str = record_str.decode('utf-8')
                                record = json.loads(record_str) if isinstance(record_str, str) else record_str
                                
                                qid_str = qid.decode('utf-8') if isinstance(qid, bytes) else qid
                                question_ids.append(qid_str)
                                answer_records[qid_str] = record.get("is_correct", False)
                            except:
                                pass
                    except:
                        pass
                
                # 批量获取题目信息（避免循环调用）
                from app.db.question_bank import get_question_by_id
                from app.services.difficulty_service import difficulty_service
                
                # 限制处理数量，避免阻塞
                max_questions = 200  # 最多处理200道题
                question_ids = question_ids[:max_questions]
                
                for qid in question_ids:
                    try:
                        question = get_question_by_id(qid)
                        if not question:
                            continue
                        
                        is_correct = answer_records.get(qid, False)
                        
                        # 统计科目错误率
                        subject = question.get("subject", "unknown")
                        if subject not in weak_subjects:
                            weak_subjects[subject] = {"total": 0, "wrong": 0}
                        weak_subjects[subject]["total"] += 1
                        if not is_correct:
                            weak_subjects[subject]["wrong"] += 1
                        
                        # 统计知识点错误率
                        knowledge_points = question.get("knowledge_points", [])
                        for kp in knowledge_points:
                            if kp not in weak_knowledge_points:
                                weak_knowledge_points[kp] = {"total": 0, "wrong": 0}
                            weak_knowledge_points[kp]["total"] += 1
                            if not is_correct:
                                weak_knowledge_points[kp]["wrong"] += 1
                        
                        # 统计难度错误率
                        difficulty = difficulty_service.get_difficulty_level(question.get("question_id"))
                        if difficulty not in weak_difficulties:
                            weak_difficulties[difficulty] = {"total": 0, "wrong": 0}
                        weak_difficulties[difficulty]["total"] += 1
                        if not is_correct:
                            weak_difficulties[difficulty]["wrong"] += 1
                    except:
                        pass
            except Exception as e:
                print(f"获取薄弱环节分析失败: {e}")
        
        # 计算错误率并排序
        weak_subjects_list = []
        for subject, stats in weak_subjects.items():
            if stats["total"] >= 3:  # 至少做3道题才统计
                error_rate = (stats["wrong"] / stats["total"]) * 100
                weak_subjects_list.append({
                    "subject": subject,
                    "error_rate": round(error_rate, 1),
                    "total": stats["total"],
                    "wrong": stats["wrong"]
                })
        weak_subjects_list.sort(key=lambda x: x["error_rate"], reverse=True)
        
        weak_knowledge_points_list = []
        for kp, stats in weak_knowledge_points.items():
            if stats["total"] >= 2:  # 至少做2道题才统计
                error_rate = (stats["wrong"] / stats["total"]) * 100
                weak_knowledge_points_list.append({
                    "knowledge_point": kp,
                    "error_rate": round(error_rate, 1),
                    "total": stats["total"],
                    "wrong": stats["wrong"]
                })
        weak_knowledge_points_list.sort(key=lambda x: x["error_rate"], reverse=True)
        
        weak_difficulties_list = []
        for difficulty, stats in weak_difficulties.items():
            if stats["total"] >= 3:
                error_rate = (stats["wrong"] / stats["total"]) * 100
                weak_difficulties_list.append({
                    "difficulty": difficulty,
                    "error_rate": round(error_rate, 1),
                    "total": stats["total"],
                    "wrong": stats["wrong"]
                })
        weak_difficulties_list.sort(key=lambda x: x["error_rate"], reverse=True)
        
        # 生成改善建议
        recommendations = []
        if weak_subjects_list and weak_subjects_list[0]["error_rate"] > 50:
            subject_name = weak_subjects_list[0]["subject"]
            recommendations.append(f"建议重点加强 {subject_name} 科目的学习，当前错误率 {weak_subjects_list[0]['error_rate']:.1f}%")
        
        if weak_knowledge_points_list and weak_knowledge_points_list[0]["error_rate"] > 50:
            kp_name = weak_knowledge_points_list[0]["knowledge_point"]
            recommendations.append(f"建议重点复习知识点：{kp_name}，当前错误率 {weak_knowledge_points_list[0]['error_rate']:.1f}%")
        
        if weak_difficulties_list and weak_difficulties_list[0]["error_rate"] > 50:
            diff_name = weak_difficulties_list[0]["difficulty"]
            recommendations.append(f"建议加强 {diff_name} 难度题目的练习，当前错误率 {weak_difficulties_list[0]['error_rate']:.1f}%")
        
        return {
            "user_id": user_id,
            "weak_subjects": weak_subjects_list[:5],  # 前5个薄弱科目
            "weak_knowledge_points": weak_knowledge_points_list[:10],  # 前10个薄弱知识点
            "weak_difficulties": weak_difficulties_list,
            "recommendations": recommendations
        }
    
    def _calculate_longest_streak(self, study_days: set) -> int:
        """计算最长连续学习天数"""
        if not study_days:
            return 0
        
        sorted_dates = sorted([datetime.strptime(d, "%Y-%m-%d").date() for d in study_days])
        if not sorted_dates:
            return 0
        
        longest = 1
        current = 1
        
        for i in range(1, len(sorted_dates)):
            if (sorted_dates[i] - sorted_dates[i-1]).days == 1:
                current += 1
                longest = max(longest, current)
            else:
                current = 1
        
        return longest
    
    async def get_visualization_data(self, user_id: str) -> Dict[str, Any]:
        """
        获取可视化数据（优化版本：限制扫描数量，避免阻塞）
        
        Returns:
            {
                "knowledge_heatmap": Dict,  # 知识点热力图
                "thinking_radar": Dict,  # 思维雷达图
                "learning_curve": List[Dict]  # 学习曲线
            }
        """
        # 统计各科目数据
        subject_stats = {}
        thinking_scores = {
            "logical_reasoning": 0,
            "case_analysis": 0,
            "legal_application": 0,
            "speed": 0,
            "accuracy": 0
        }
        learning_curve = []
        
        if self.redis:
            try:
                # 扫描所有每日记录（限制扫描数量，避免阻塞）
                pattern = f"daily_record:{user_id}:*"
                keys = []
                cursor = 0
                max_scans = 10  # 最多扫描10次
                scan_count = 0
                
                while scan_count < max_scans:
                    cursor, batch = self.redis.scan(cursor, match=pattern, count=50)  # 减少每次扫描数量
                    keys.extend(batch)
                    scan_count += 1
                    if cursor == 0:
                        break
                    if len(keys) >= 50:  # 限制最多处理50个日期
                        break
                
                # 按日期排序处理
                sorted_keys = sorted(keys, key=lambda k: k.split(':')[-1])
                cumulative_correct = 0
                cumulative_total = 0
                
                for key in sorted_keys:
                    date_str = key.split(':')[-1]
                    records = self.redis.hgetall(key)
                    
                    day_correct = 0
                    day_total = 0
                    
                    for qid, record_str in records.items():
                        try:
                            if isinstance(record_str, bytes):
                                record_str = record_str.decode('utf-8')
                            record = json.loads(record_str) if isinstance(record_str, str) else record_str
                            
                            day_total += 1
                            cumulative_total += 1
                            if record.get("is_correct", False):
                                day_correct += 1
                                cumulative_correct += 1
                            
                            # 统计科目数据（如果有subject字段）
                            # 这里简化处理，实际应该从题目数据中获取
                            
                            # 统计思维分析数据
                            thinking_analysis = record.get("thinking_analysis")
                            if thinking_analysis:
                                if isinstance(thinking_analysis, str):
                                    thinking_analysis = json.loads(thinking_analysis)
                                score = thinking_analysis.get("thinking_quality_score", 70)
                                thinking_scores["logical_reasoning"] = max(thinking_scores["logical_reasoning"], score)
                                thinking_scores["case_analysis"] = max(thinking_scores["case_analysis"], score)
                        except:
                            pass
                    
                    if day_total > 0:
                        day_accuracy = (day_correct / day_total * 100)
                        cumulative_accuracy = (cumulative_correct / cumulative_total * 100) if cumulative_total > 0 else 0
                        learning_curve.append({
                            "date": date_str,
                            "cumulative_accuracy": round(cumulative_accuracy, 1)
                        })
            except Exception as e:
                print(f"Redis操作失败: {e}")
        
        # 如果Redis不可用，尝试从训练服务的内存存储读取
        if not self.redis:
            try:
                from app.services.training_service import training_service
                if hasattr(training_service, '_daily_records'):
                    for record_key, records in training_service._daily_records.items():
                        if record_key.startswith(f"{user_id}:"):
                            date_str = record_key.split(':', 1)[1]
                            records_list = sorted(records.items(), key=lambda x: x[1].get("timestamp", ""))
                            
                            day_correct = 0
                            day_total = 0
                            
                            for qid, record in records.items():
                                day_total += 1
                                cumulative_total += 1
                                if record.get("is_correct", False):
                                    day_correct += 1
                                    cumulative_correct += 1
                            
                            if day_total > 0:
                                day_accuracy = (day_correct / day_total * 100)
                                cumulative_accuracy = (cumulative_correct / cumulative_total * 100) if cumulative_total > 0 else 0
                                learning_curve.append({
                                    "date": date_str,
                                    "cumulative_accuracy": round(cumulative_accuracy, 1)
                                })
            except Exception as e:
                print(f"从训练服务读取记录失败: {e}")
        
        # 如果没有思维分析数据，使用默认值
        if all(v == 0 for v in thinking_scores.values()):
            thinking_scores = {
                "logical_reasoning": 70,
                "case_analysis": 70,
                "legal_application": 70,
                "speed": 70,
                "accuracy": 70
            }
        
        # 如果没有科目数据，使用默认值
        if not subject_stats:
            subject_stats = {
                "contract_law": {"score": 0, "practice_count": 0},
                "criminal_law": {"score": 0, "practice_count": 0},
                "civil_procedure": {"score": 0, "practice_count": 0},
                "criminal_procedure": {"score": 0, "practice_count": 0}
            }
        
        return {
            "user_id": user_id,
            "knowledge_heatmap": subject_stats,
            "thinking_radar": thinking_scores,
            "learning_curve": learning_curve[-7:] if learning_curve else []  # 最近7天
        }


progress_service = ProgressService()

